#include <iostream>
#include <cstring>
#include <string>
using namespace std;

class CowString{
    class CharProxy{
    public:
        CharProxy(CowString & self, size_t idx)
        : _self(self)
        , _idx(idx)
        {}

        char operator=(char ch);

        operator char(){ // 类型转换函数，可以进行类型转化为char，返回一个临时值char
            return _self._pstr[_idx];
        }

        friend
        ostream & operator<<(ostream & os, const CharProxy & rhs);


    private:
        CowString & _self; 
        size_t _idx;
    };

public:
    CowString();
    CowString(const char *);//有参构造
    ~CowString();
    CowString(const CowString&);
    CowString& operator=(const CowString&);

    CharProxy operator[](size_t idx);

    const char * c_str() const {
        return _pstr;
    }

    size_t size() const {
        return strlen(_pstr);
    }


    size_t use_count(){
        return *(int *)(_pstr - kRefcountLength);
    }

    friend
    ostream& operator<<(ostream & os, const CowString & rhs);

    friend
    ostream & operator<<(ostream & os, const CharProxy & rhs);

private:
    void initRefcount(){
        *(int *)(_pstr - kRefcountLength) = 1;
    }

    void increaseRefcount(){
        ++*(int *)(_pstr - kRefcountLength);
    }

    void descreaseRefcount(){
        --*(int *)(_pstr - kRefcountLength);
    }

    char * malloc(const char * pstr = nullptr){
        if (pstr){
            return new char[strlen(pstr) + 1 + kRefcountLength]() + kRefcountLength;
        } else {
            return new char[1 + kRefcountLength]() + kRefcountLength;
        }
    }
    void release(){
        descreaseRefcount();
        if (use_count() == 0){
            delete [] (_pstr - kRefcountLength);
            cout << ">>>>> delete heap" << endl;
        }
        _pstr = nullptr;
    }

private:
    char * _pstr;
    static const int kRefcountLength;
};
const int CowString::kRefcountLength = 4;

ostream& operator<<(ostream &os, const CowString & rhs){
    os << rhs._pstr;
    return os;
}

CowString::CowString()
:_pstr(malloc()){
    initRefcount();
    cout << "CowString()" << endl;
}

CowString::CowString(const char * pstr)
:_pstr(malloc(pstr))
{
    initRefcount();
    strcpy(_pstr, pstr);
    cout << "CowString(const char *)" << endl;    
}

CowString::~CowString(){
    cout << "~CowString" << endl;
    release();
}
CowString::CowString(const CowString& rhs)
:_pstr(rhs._pstr) // 浅拷贝
{
    increaseRefcount();
    cout << "CowString拷贝构造" << endl;
}

CowString& CowString::operator=(const CowString& rhs){
    if (this != &rhs){
        release(); // 判断加回收
        _pstr = rhs._pstr;
        increaseRefcount();
    }
    return *this;
}

// 读时写时都复制
// char & CowString::operator[](size_t idx){
//     if (idx < size()){
//         if (use_count() > 1){
//             // 原空间的引用计数 - 1
//             descreaseRefcount();
//             // 进行深拷贝
//             char * tmp = malloc(_pstr);
//             strcpy(tmp, _pstr);
//             // 改变指向，让新的_pstr指向新空间
//             _pstr = tmp;
//             // 初始化引用计数
//             initRefcount();
//         }
//         return _pstr[idx];
//     } else {
//         cout << "out of range" << endl;
//         static char nullchar = '\0';
//         return nullchar;
//     }
// }

CowString::CharProxy CowString::operator[](size_t idx){
    return CharProxy(*this, idx);
}

// str[0] = 'H';
char CowString::CharProxy::operator=(char ch){
    if (_idx < _self.size()){
        if (_self.use_count() > 1){
            // 原空间的引用计数 - 1
            _self.descreaseRefcount();
            // 进行深拷贝
            char * tmp = _self.malloc(_self._pstr);
            strcpy(tmp, _self._pstr);
            // 改变指向，让新的_pstr指向新空间
            _self._pstr = tmp;
            // 初始化引用计数
            _self.initRefcount();
        }
        _self._pstr[_idx] = ch;
        return _self._pstr[_idx];
    } else {
        cout << "out of range" << endl;
        static char nullchar = '\0';
        return nullchar;
    }
}

// cout << str[1] << endl;
ostream & operator<<(ostream & os, const CowString::CharProxy & rhs){
    if (rhs._idx < rhs._self.size()){
        os << rhs._self._pstr[rhs._idx];
    } else {
        os << "out of range";
    }
    return os;
}


void test0(){
    CowString str1;
    CowString str2 = str1;
    cout << "str1 = " << str1 << endl;
    cout << "str2 = " << str2 << endl;
    cout << "str1.use_count = " << str1.use_count() << endl;
    cout << "str2.use_count = " << str2.use_count() << endl;
    
    cout << endl;
    CowString str3("hello");
    CowString str4 = str3;
    cout << "str3 = " << str3 << endl;
    cout << "str4 = " << str4 << endl;
    cout << "str3.use_count = " << str3.use_count() << endl;
    cout << "str4.use_count = " << str4.use_count() << endl;

    cout << endl;
    str1 = str3;
    cout << "str1 = " << str1 << endl;
    cout << "str3 = " << str3 << endl;
    cout << "str1.use_count = " << str1.use_count() << endl;
    cout << "str3.use_count = " << str3.use_count() << endl;
}

void test1(){
    CowString str1("hello");
    cout << str1[4] << endl;
    CowString str2 = str1;

    str1[0] = 'H'; // 去下标进行写操作时，需要用到写时复制Cow
    cout << str1 << endl;
    cout << str2 << endl;

    // 问题
    char ch = 'a';
    ch = str1[0];
    cout << ch << endl;
}

int main(void){
    test1();
    return 0;
}

